package com.zkthink.ceres.shoppingcart.service.impl;

import com.alibaba.fastjson.JSON;
import com.zkthink.base.R;
import com.zkthink.cache.repository.CacheRepository;
import com.zkthink.ceres.common.enums.StoreDailyStatisticEnum;
import com.zkthink.ceres.product.vo.ShoppingCartSkuItemVO;
import com.zkthink.ceres.store.service.StoreService;
import com.zkthink.database.mybatis.conditions.Wraps;
import com.zkthink.ceres.product.service.ProductService;
import com.zkthink.ceres.product.vo.ShoppingCartSkuVO;
import com.zkthink.ceres.shoppingcart.converter.ShoppingCartBeanConverter;
import com.zkthink.ceres.shoppingcart.dao.ShoppingCartMapper;
import com.zkthink.ceres.shoppingcart.dto.ShoppingCartSkuDTO;
import com.zkthink.ceres.shoppingcart.entity.ShoppingCart;
import com.zkthink.ceres.shoppingcart.service.ShoppingCartService;
import com.zkthink.base.service.SuperServiceImpl;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 购物车表
 * </p>
 *
 * @author vivi.huang
 * @date 2020-05-18
 */
@Slf4j
@Service
@AllArgsConstructor
public class ShoppingCartServiceImpl extends SuperServiceImpl<ShoppingCartMapper, ShoppingCart> implements ShoppingCartService {

    public static final String SHOPPINGCART = "shoppingcart#";

    private ProductService productService;
    private CacheRepository redisRepository;
    private ShoppingCartBeanConverter converter;
    private StoreService storeService;

    @Override
    public R<List<ShoppingCartSkuVO>> saveShoppingCart(Long memberId, ShoppingCartSkuVO shoppingCartSkuVO) {

        //先把已存在的购物车查询出来
        List<ShoppingCartSkuVO> existedShoppingCartSkuVOList = this.getShoppingCart(memberId).getData();

        //合并新旧购物车，找出已存在商品，则数量+n
        List<ShoppingCartSkuVO> targetList = mergeNewAndExistedShoppingCart(shoppingCartSkuVO, existedShoppingCartSkuVOList);

        saveOrUpdateToCache(memberId, targetList);
        saveOrUpdateToDatabase(memberId, targetList);
        //埋点
        storeService.addStorePoint(shoppingCartSkuVO.getStoreId(), StoreDailyStatisticEnum.PV);
        return R.success(targetList);
    }

    private List<ShoppingCartSkuVO> mergeNewAndExistedShoppingCart(ShoppingCartSkuVO newShoppingCartSkuVO, List<ShoppingCartSkuVO> oldShoppingCartSkuVOList) {

        //如果用户没有添加过购物，直接返回新的
        if (CollectionUtils.isEmpty(oldShoppingCartSkuVOList)) {
            return Arrays.asList(newShoppingCartSkuVO);
        }


        boolean isExisted = false;
        for (ShoppingCartSkuVO shoppingCartSkuVO: oldShoppingCartSkuVOList) {

            //如果以存在的商家
            if (newShoppingCartSkuVO.getStoreId().longValue() == shoppingCartSkuVO.getStoreId().longValue()) {
                //合并商品列表
                List<ShoppingCartSkuItemVO> targetSkuList = mergeNewAndExistedSkuList(newShoppingCartSkuVO.getShoppingCartSkuItemList(), shoppingCartSkuVO.getShoppingCartSkuItemList());
                shoppingCartSkuVO.setShoppingCartSkuItemList(targetSkuList);
                isExisted = true;
                break;
            }
        }

        if (!isExisted) {
            oldShoppingCartSkuVOList.add(newShoppingCartSkuVO);
        }

        return oldShoppingCartSkuVOList;
    }

    /**
     * 比对相同商家的新旧商品
     * 如果存在 数量加1 ，如果不存在，直接放在队列后
     * @param newSkuItemList
     * @param oldSkuItemList
     * @return
     */
    private List<ShoppingCartSkuItemVO> mergeNewAndExistedSkuList(List<ShoppingCartSkuItemVO> newSkuItemList, List<ShoppingCartSkuItemVO> oldSkuItemList) {

        if (newSkuItemList.size() > 1) {
            throw new RuntimeException("添加购物车接口每次添加一个商品");
        }

        ShoppingCartSkuItemVO newSku = newSkuItemList.get(0);

        boolean isExisted = false;
        for (ShoppingCartSkuItemVO s: oldSkuItemList) {

            //如果商品存在  添加数量
            if (s.getId().longValue() == newSku.getId().longValue()) {
                s.setBuyNum(s.getBuyNum() + newSku.getBuyNum());
                isExisted = true;
                break;
            }
        }

        if (!isExisted) {
            oldSkuItemList.add(newSku);
        }

        return oldSkuItemList;
    }

    private void saveOrUpdateToDatabase(Long memberId, List<ShoppingCartSkuVO> shoppingCartSkuVOList) {
        //先删后增
        this.remove(Wraps.<ShoppingCart>lbQ().in(ShoppingCart::getMemberId, memberId));
        this.saveBatch(converter.convertToShoppingSaveDTOList(memberId, shoppingCartSkuVOList));
    }

    private void saveOrUpdateToCache(Long memberId, List<ShoppingCartSkuVO> shoppingCartSkuVOList) {
        saveOrUpdateToCache0(memberId, converter.convertToSkuDTOList(shoppingCartSkuVOList));
    }

    private void saveOrUpdateToCache0(Long memberId, List<ShoppingCartSkuDTO> shoppingCartSkuDTOList) {
        redisRepository.set(createShoppingCartCacheKey(memberId), JSON.toJSONString(shoppingCartSkuDTOList));
    }

    private String createShoppingCartCacheKey(Long memberId) {
        return SHOPPINGCART + memberId;
    }

    @Override
    public R<List<ShoppingCartSkuVO>> updateShoppingCart(Long memberId, List<ShoppingCartSkuVO> shoppingCartSkuVOList) {
        saveOrUpdateToCache(memberId, shoppingCartSkuVOList);
        saveOrUpdateToDatabase(memberId, shoppingCartSkuVOList);
        return R.success(shoppingCartSkuVOList);
    }

    @Override
    public R<List<ShoppingCartSkuVO>> getShoppingCart(Long memberId) {
        //从缓存获取购物车数据
        List<ShoppingCartSkuDTO> shoppingCartSkuDTOS = getSkuIdListFromCache(memberId);

        if (CollectionUtils.isEmpty(shoppingCartSkuDTOS)) {
            return R.success(Lists.newArrayList());
        }

        //以sku id 分组
        Map<Long, ShoppingCartSkuDTO> map = shoppingCartSkuDTOS.stream().collect(Collectors
                .toMap(ShoppingCartSkuDTO::getId, m ->m, (o1, o2) -> o2));

        //以store id 分组
        Map<Long, List<ShoppingCartSkuDTO>> groupByStoreIdMap = shoppingCartSkuDTOS.stream().collect(Collectors
                .groupingBy(ShoppingCartSkuDTO::getStoreId));

        //从产品接口获取具体sku数据
        R<List<ShoppingCartSkuVO>> r = productService.assembleShoppingCartSku(
                shoppingCartSkuDTOS.stream().map(ShoppingCartSkuDTO::getId).collect(Collectors.toList()));


        r.getData().forEach(shoppingCartSkuVO -> {
            //填充当前店铺是否选上标记
            List<ShoppingCartSkuDTO> skuList = groupByStoreIdMap.get(shoppingCartSkuVO.getStoreId());
            shoppingCartSkuVO.setSelected(skuList.get(0).getStoreSelected());

            //循环商品
            shoppingCartSkuVO.getShoppingCartSkuItemList().forEach(shoppingCartSkuItemVO -> {
                ShoppingCartSkuDTO shoppingCartSkuDTO = map.get(shoppingCartSkuItemVO.getId());
                //填充商品是否选上标记
                shoppingCartSkuItemVO.setSelected(shoppingCartSkuDTO.getSelected());
                //商品的购买数量
                shoppingCartSkuItemVO.setBuyNum(shoppingCartSkuDTO.getBuyNum());
            });
        });

        return r;
    }

    private List<ShoppingCartSkuDTO> getSkuIdListFromCache(Long memberId) {
        String json = redisRepository.get(createShoppingCartCacheKey(memberId));
        if (null == json) {
            return Lists.newArrayList();
        }
        List<ShoppingCartSkuDTO> shoppingCartSkuDTOS = JSON.parseArray(json, ShoppingCartSkuDTO.class);
        return shoppingCartSkuDTOS;
    }

    @Override
    public R<Boolean> deleteShoppingCart(Long memberId) {
        deleteSkuOfShoppingCartFromCache(memberId);
        deleteSkuOfShoppingCartFromDatabase(memberId);
        return R.success(true);
    }

    @Override
    public R<Boolean> deletePartOfSkuFromShoppingCart(Long memberId, List<Long> skuIdList) {
        deletePartOfSkuFromCache(memberId, skuIdList);
        deletePartOfSkuFromDB(memberId, skuIdList);
        return R.success(true);
    }

    private void deletePartOfSkuFromDB(Long memberId, List<Long> skuIdList) {
        this.remove(Wraps.<ShoppingCart>lbQ().eq(ShoppingCart::getMemberId, memberId).in(ShoppingCart::getSkuId, skuIdList));
    }

    private void deletePartOfSkuFromCache(Long memberId, List<Long> skuIdList) {
        List<ShoppingCartSkuDTO> shoppingCartSkuDTOS = getSkuIdListFromCache(memberId);
        List<ShoppingCartSkuDTO> targetList = shoppingCartSkuDTOS.stream().filter(f -> !skuIdList.contains(f.getId())).collect(Collectors.toList());
        saveOrUpdateToCache0(memberId, targetList);
    }

    private void deleteSkuOfShoppingCartFromDatabase(Long memberId) {
        this.remove(Wraps.<ShoppingCart>lbQ().eq(ShoppingCart::getMemberId, memberId));
    }

    private void deleteSkuOfShoppingCartFromCache(Long memberId) {
        this.redisRepository.del(createShoppingCartCacheKey(memberId));
    }
}
